import { useCallback, useReducer, useState } from "react";
import { useMountedRef } from "utils";

interface State<D> {
  error: Error | null;
  data: D | null;
  stat: "idle" | "loading" | "error" | "success";
}
const initialDefaultState: State<null> = {
  //默认初始状态
  stat: "idle",
  data: null,
  error: null,
};
const defaultConfig = {
  throwOnError: false,
};

const useSafeDispatch = <T>(dispatch: (...args: T[]) => void) => {
  const mountedRef = useMountedRef();
  return useCallback(
    (...args: T[]) => {
      mountedRef.current ? dispatch(...args) : void 0;
    },
    [dispatch, mountedRef],
  );
};
export const useAsync = <D>(
  initialstate?: State<D>,
  initialConfig?: typeof defaultConfig,
) => {
  const config = { ...defaultConfig, ...initialConfig };
  const [state, dispatch] = useReducer(
    (state: State<D>, action: Partial<State<D>>) => {
      return { ...state, ...action };
    },
    {
      ...initialDefaultState,
      ...initialstate,
    },
  );
  const safeDispatch = useSafeDispatch(dispatch);

  const setData = useCallback(
    (data: D) => safeDispatch({ stat: "success", data, error: null }),
    [safeDispatch],
  );
  const setError = useCallback(
    (error: Error) => safeDispatch({ error, stat: "error", data: null }),
    [safeDispatch],
  );
  const [retry, setRetry] = useState(() => () => {});
  //run 用来触发异步请求
  const run = useCallback(
    (promise: Promise<D>, runConfig?: { retry: () => Promise<D> }) => {
      if (!promise || !promise.then) {
        throw new Error("请传入promise类型数据");
      }
      setRetry(() => () => {
        if (runConfig?.retry) {
          run(runConfig?.retry(), runConfig);
        }
      });
      safeDispatch({ stat: "loading" });
      return promise
        .then((data: D) => {
          //console.log("查查查查---", data);
          setData(data);
          return data;
        })
        .catch((error: Error) => {
          //catch会主动消化异常，如果不抛出，外面是接收不到异常的
          setError(error);
          if (config.throwOnError) {
            return Promise.reject(error);
          }
        });
    },
    [config.throwOnError, setData, setError, safeDispatch],
  );
  return {
    isIdle: state.stat === "idle",
    isLoading: state.stat === "loading",
    isError: state.stat === "error",
    isSuccess: state.stat === "success",
    run,
    setData,
    setError,
    //retry 被调用时重新跑一遍run
    retry,
    ...state,
  };
};
